<?php
/*
Plugin Name: WP-prettyPhoto
Plugin URI: http://blog.fusi0n.org/category/wp-prettyphoto
Description: WP-prettyPhoto allows you to use <a href="http://www.no-margin-for-errors.com/projects/prettyPhoto/" alt="prettyPhoto">prettyPhoto</a> by <a href="http://www.no-margin-for-errors.com/">Stéphane Caron</a>, a jQuery-powered Lightbox clone with WordPress.
Version: 1.4.1
Author: Pier-Luc Petitclerc
Author URI: http://blog.fusi0n.org
Text Domain: wp-prettyphoto
*/

class WP_prettyPhoto {

  /**
   * @var array WP-prettyPhoto Options (Since 1.4, this also contains options default and current values and descriptions)
   * @access private
   * @since 1.3
  */
  private $opts = array();

  /**
   * Class constructor
   * Sets default options, add filters and options page.
   * @author Pier-Luc Petitclerc <pL@fusi0n.org>
   * @param null
   * @return void
   * @since 1.2
   * @access public
  */
  public function __construct() {
    $this->_buildOptions();
    $wpurl = WP_PLUGIN_URL.'/'.str_replace(basename( __FILE__), '', plugin_basename(__FILE__));
    if (!is_admin()) {
      if ($this->wppp_jsreplace == 1) {
        // jQuery - removing to make sure we're using 1.3.2
        wp_deregister_script('jquery');
        wp_register_script('jquery', $wpurl.'/js/jquery-1.3.2.min.js', false, '1.3.2');
        wp_enqueue_script('jquery');
      }
      // prettyPhoto JavaScript
      wp_register_script('prettyphoto', $wpurl.'/js/jquery.prettyPhoto.js', array('jquery'), '2.4.3');
      wp_enqueue_script('prettyphoto');
      // prettyPhoto CSS
      wp_enqueue_style('prettyphoto', $wpurl.'/css/prettyPhoto.css', false, '2.4');
    }
    else {
      $this->loadLocale(get_locale());
      add_action('admin_init', array(&$this, 'wppp_section_register'));
      add_action('plugin_action_links_'.plugin_basename(__FILE__), array(&$this, 'wppp_plugin_links'));
    }
    $putJS = $this->wppp_bottom? 'wp_footer' : 'wp_head';
    add_action($putJS, array(&$this, 'wppp_styles'));
    if ($this->_doOutput()) {
      add_filter('the_content', array(&$this, 'wppp_content_hook'), 99, 1);
      add_filter('the_excerpt', array(&$this, 'wppp_content_hook'), 99, 1);
    }
  }

  /**
   * Overload hack
   * @param string $name Function name
   * @param mixed $args Arguments
   * @return null
   * @access public
   * @author Pier-Luc Petitclerc <pL@fusi0n.org>
   * @since 1.4
  */
  public function __call($name, $args) {
    if (!function_exists($name) || !method_exists($this, $name)) {
      if (substr($name, 0, 14) == 'wppp_settings_') {
        $setting = str_replace('wppp_settings_', '', $name);
        $this->wppp_settings($this->opts[$setting], $setting);
      }
      elseif ((substr($name, 0, 13) == 'wppp_section_') && ($name != 'wppp_section_callback')) {
        $section = str_replace('wppp_section_', '', $name);
        $this->wppp_section_callback($section);
      }
    }
  }

  /**
   * Overloading hack/shortcut to retrieve option value
   * @param string $name Option Name (Key in the array without wppp_ prefix)
   * @return array Option data
   * @access public
   * @author Pier-Luc Petitclerc <pL@fusi0n.org>
   * @since 1.4.1
  */
  public function __get($name) {
    $name = (substr($name,0,5) == 'wppp_')? $name : 'wppp_'.$name;
    return $this->wppp_get_option($name);
  }

  /**
   * Produces options output
   * @author Pier-Luc Petitclerc <pL@fusi0n.org>
   * @param void
   * @return bool
   * @since 1.3.3
   * @access private
  */
  private function _doOutput() {
    $a = array('wppp_automate_all', 'wppp_automate_img', 'wppp_automate_swf', 'wppp_automate_mov', 'wppp_automate_yt', 'wppp_automate_ext');
    foreach ($a as $i) {
      if ($this->$i == 1) return true;
    }
    return false;
  }

  /** Plugin activation hook used to set default option values
   * @param null
   * @return void
   * @since 1.4
   * @author Pier-Luc Petitclerc <pL@fusi0n.org>
   * @access public
  */
  public function wppp_activation_hook() {
    foreach ($this->opts as $k=>$v) {
      // register_setting($option_group, $option_name, $sanitize_callback = )
      register_setting('media', $k);
			if (get_option($k) === false) { update_option($k, $this->opts[$k]['default']); }
    }
  }

  /**
   * Option page (section) registration hook
   * @param void
   * @return null
   * @author Pier-Luc Petitclerc <pL@fusi0n.org>
   * @access public
   * @since 1.4
  */
  public function wppp_section_register() {
    // add_settings_section($id, $title, $callback, $page)
    add_settings_section('wp-prettyphoto', 'WP-prettyPhoto Options', array(&$this, 'wppp_section_callback'), 'media');
    add_settings_section('wppp_automate', 'Automation', array(&$this, 'wppp_section_automate'), 'media');
    add_settings_section('wppp_appearance', 'Appearance', array(&$this, 'wppp_section_appearance'), 'media');
    add_settings_section('wppp_technical', 'Technical', array(&$this, 'wppp_section_technical'), 'media');
    foreach ($this->opts as $optName => $optVal) {
      // add_settings_field($id, $title, $callback, $page, $section = 'default', $args = array())
      add_settings_field($optName, $optVal['name'], array(&$this, 'wppp_settings_'.$optName), 'media', 'wppp_'.$optVal['section']);
    }
  }

  /**
   * Outputs settings section header text
   * @param null
   * @return void
   * @access public
   * @since 1.4
   * @author Pier-Luc Petitclerc <pL@fusi0n.org>
   * @see http://codex.wordpress.org/Settings_API#Adding_Settings_Sections
  */
  public function wppp_section_callback($s=null) {
    switch ($s) {
      case 'automate':
        echo '<p>'.__('Automatic prettyfying options.').'</p>';
      break;
      case 'appearance':
        echo '<p>'.__('Below is a list of the prettyPhoto themes you have installed. To learn more about themeing prettyPhoto, refer to the <a href="http://blog.fusi0n.org/wp-prettyphoto/technical-information-and-usage-instructions#theming" target="_blank">documentation</a>.</p>');
      break;
      case 'technical':
        echo '<p>'.__('Technical settings').'.</p>';
      break;
    }
  }

  /**
   * Outputs settings for the settings page
   * I *really* don't like to output directly from a function but apparently there's no other way
   * I'll use include, but it sure as hell ain't prettier. Don't hold it against me.
   * @param null
   * @return void
   * @since 1.4
   * @author Pier-Luc Petitclerc <pL@fusi0n.org>
  */
  public function wppp_settings($v, $k) {
    $last = array_pop(array_keys($this->opts));
    if (isSet($v['values'])) {
      $e = '';
      foreach ($v['values'] as $childVal) {
        $e .= ($v['current'] == $childVal)? "<option value='$childVal' selected='selected'>$childVal</option>\n" : "<option value='$childVal'>$childVal</option>\n";
      }
      echo '<select name="'.$k.'" id="'.$k.'">'.$e.'</select>';
    }
    elseif (is_bool($v['default']) || is_int($v['default'])) {
      $checked = $v['current'] == 1? ' checked="checked"' : '';
      echo '<input type="checkbox" value="1" id="'.$k.'" name="'.$k.'"'.$checked.' /> <label for="'.$k.'">'.$v['desc'].'</label>';
    }
    elseif (is_string($v['default'])) {
      if ($k == 'wppp_callback') {
        echo '<label for="'.$k.'">'.$v['desc'].'</label><br /><textarea cols="50" rows="10" id="'.$k.'" name="'.$k.'">'.$v['current'].'</textarea>';
      }
      else {
        echo '<input type="text" value="'.$v['current'].'" name="'.$k.'" id="'.$k.'"> <label for="'.$k.'">'.$v['desc'].'</label>';
      }
    }
    settings_fields('media');
    echo "<br />\n";
  }

  /**
   * Adds Settings and Documentation links to plugin's links because people obviously can't find it...
   * Note to self: Never underestimate the power of stupid people in large groups.
   * @param array $links Already present links
   * @return array Links array containing Settings & Documentation
   * @access public
   * @author Pier-Luc Petitclerc <pL@fusi0n.org>
   * @since 1.4.2
  */
  public function wppp_plugin_links($links) {
    $additionalLinks = array('<a href="options-media.php">'.__('Settings').'</a>',
                             '<a href="http://blog.fusi0n.org/wp-prettyphoto/technical-information-and-usage-instructions">'.__('Documentation').'</a>');
    return array_merge($additionalLinks, $links);
  }

  /**
   * Replaces occurences of $wppp_rel with the prettyPhoto rel hook
   * @param string $content Post/page contents
   * @return string Prettified post/page contents
   * @author Rupert Morris
   * @author Tanin "Regular Expression God"
   * @author Pier-Luc Petitclerc <pL@fusi0n.org>
   * @since 1.0
   * @link http://0xtc.com/2008/05/27/auto-lightbox-function.xhtml
   * @access public
  */
  public function wppp_content_hook($content) {
    $fileTypes        = $this->_getFileTypes(array('type'=>'all','context'=>true));
    $pattern          = array();
    $rel              = $this->wppp_rel;
    $pattern[]        = "/<a(.*?)href=('|\")([A-Za-z0-9\/_\.\~\:-]*?)($fileTypes)('|\")(.*?)>/i";
    $pattern[]        = "/<a(.*?)href=('|\")([A-Za-z0-9\/_\.\~\:-]*?)($fileTypes)('|\")(.*?)(rel=('|\")".$rel."(.*?)('|\"))([ \t\r\n\v\f]*?)((rel=('|\")".$rel."(.*?)('|\"))?)([ \t\r\n\v\f]?)([^\>]*?)>/i";
    if ($this->wppp_automate_yt) { $pattern[] = '/<a(.*?)href=(\'|")(http:\/\/www\.youtube\.com\/watch\?v=[A-Za-z0-9]*)(\'|")(.*?)>/i'; }
    if ($this->wppp_automate_ext) { $pattern[] = '/<a(.*?)href=(\'|")(.*iframe=true.*)(\'|")(.*?)>/i'; }
    return preg_replace_callback($pattern, array(&$this,'_regexCallback'), $content);
  }

  /**
   * Callback function used to detect whether a string contains a link to a _blank target
   * @param array $matches Regular Expression matches from preg_replace()
   * @return bool True if _blank was found in matches, false if it wasn't
   * @global object $post
   * @author Pier-Luc Petitclerc <pL@fusi0n.org>
   * @see wppp_content_hook
   * @since 1.2.1
   * @access private
  */
  private function _regexCallback($matches) {
    global $post;
    $rel            = $this->wppp_rel;
    $pattern        = array();
    $replacement    = array();
    $pattern[]      = "/<a(.*?)href=('|\")([A-Za-z0-9\/_\.\~\:-]*?)($fileTypes)('|\")(.*?)>/i";
    $pattern[]      = "/<a(.*?)href=('|\")([A-Za-z0-9\/_\.\~\:-]*?)($fileTypes)('|\")(.*?)(rel=('|\")".$rel."(.*?)('|\"))([ \t\r\n\v\f]*?)((rel=('|\")".$rel."(.*?)('|\"))?)([ \t\r\n\v\f]?)([^\>]*?)>/i";
    $replacement[]  = '<a$1href=$2$3$4$5$6 rel="'.$rel.'[g'.$post->ID.']">';
    $replacement[]  = '<a$1href=$2$3$4$5$6$7>';

    if ($this->wppp_automate_yt) {
      $pattern[]    = '/<a(.*?)href=(\'|")(http:\/\/www\.youtube\.com\/watch\?v=[A-Za-z0-9]*)(\'|")(.*?)>/i';
      $pattern[]    = "/<a(.*?)href=('|\")(http:\/\/www\.youtube\.com\/watch\?v=[A-Za-z0-9]*)('|\")(.*?)(rel=('|\")".$rel."(.*?)('|\"))([ \t\r\n\v\f]*?)((rel=('|\")".$rel."(.*?)('|\"))?)([ \t\r\n\v\f]?)([^\>]*?)>/i";
      $replacement[]= '<a$1href=$2$3$4$5 rel="'.$rel.'[g'.$post->ID.']">';
      $replacement[]= '<a$1href=$2$3$4$5$6$7>';
    }
    if ($this->wppp_automate_ext) {
      $pattern[]    = '/<a(.*?)href=(\'|")(.*iframe=true.*)(\'|")(.*?)>/i';
      $pattern[]    = "/<a(.*?)href=('|\")(.*iframe=true.*)(.*?)(rel=('|\")".$rel."(.*?)('|\"))([ \t\r\n\v\f]*?)((rel=('|\")".$rel."(.*?)('|\"))?)([ \t\r\n\v\f]?)([^\>]*?)>/i";
      $replacement[]= '<a$1href=$2$3$4$5 rel="'.$rel.'[g'.$post->ID.']">';
      $replacement[]= '<a$1href=$2$3$4$5$6$7>';
    }
    return !strpos($matches['0'], '_blank')? preg_replace($pattern,$replacement,$matches['0']) : $matches['0'];
  }

  /**
   * Loads gettext localization
   * Translation file (wp-prettyphoto.mo) must be found inside "PLUGIN_DIR/lang/LOCALE_STRING"
   * @param string $locale Locale (fr_FR)
   * @return bool
   * @access private
   * @since 1.4.2
   * @author Pier-Luc Petitclerc <pL@fusi0n.org>
  */
  private function loadLocale($locale) {
    $moFile = dirname(__FILE__).'/lang/'.$locale.'/wp-prettyphoto.mo';
    if (is_dir(dirname($moFile))) {
      if (is_readable($moFile)) {
        load_plugin_textdomain('wp-prettyphoto', $moFile);
        return true;
      }
    }
    return false;
  }
  /**
   * Gets file extension(s) associated with media type
   * @param array $opts Options array
   * @param string $opts['type'] Media Type (mov, swf, img or all)
   * @param bool $opts['context'] Validate against configuration
   * @return string Pipe-separated file extension(s)
   * @author Pier-Luc Petitclerc <pL@fusi0n.org>
   * @since 1.3
   * @access private
  */
  private function _getFileTypes($opts=array()) {
    switch ($opts['type']) {
      case 'mov':
        return $opts['context']? $this->wppp_automate_mov? '\.mov' : false : '\.mov';
      break;
      case 'swf':
        return $opts['context']? $this->wppp_automate_swf? '\.swf' : false : '\.swf';
      break;
      case 'img':
        return $opts['context']? $this->wppp_automate_img? '\.bmp|\.gif|\.jpg|\.jpeg|\.png' : false : '\.bmp|\.gif|\.jpg|\.jpeg|\.png';
      break;
      case 'all':
      default:
        return $this->_getFileTypes(array('type'=>'mov', $opts['context'])).'|'.$this->_getFileTypes(array('type'=>'swf', $opts['context'])).'|'.$this->_getFileTypes(array('type'=>'img', $opts['context']));
    }
  }

  /**
   * Adds prettyPhoto in the page that is being viewed
   * @param null
   * @return void
   * @author Pier-Luc Petitclerc <pL@fusi0n.org>
   * @example add_action('wp_head', 'wppp_styles');
   * @link http://www.no-margin-for-errors.com/projects/prettyPhoto/#howtouse
   * @since 1.0
   * @access public
  */
  public function wppp_styles() {
    $output = <<<EOHTML

      <script type="text/javascript" charset="utf-8">
        $(document).ready(function(){
          $("a[rel^='{$this->opts['wppp_rel']['current']}']").prettyPhoto({
            animationSpeed: '{$this->opts['wppp_speed']['current']}',
            padding: {$this->opts['wppp_padding']['current']},
            opacity: {$this->opts['wppp_opacity']['current']},
            showTitle: {$this->opts['wppp_title']['current']},
            allowresize: {$this->opts['wppp_resize']['current']},
            counter_separator_label: '{$this->opts['wppp_counterlabel']['current']}',
            theme: '{$this->opts['wppp_theme']['current']}',
            callback: {$this->opts['wppp_callback']['current']}
          });
        });
      </script>
EOHTML;
    echo $output;
  }

  /**
   * Shortcut/hack to return option value or option default if value is not set
   * @param string $k Option Name
   * @return mixed Option Value
   * @access private
   * @since 1.4.1
   * @author Pier-Luc Petitclerc <pL@fusi0n.org>
  */
  private function wppp_get_option($k) {
    $v = get_option($k);
    return (!$v)? $this->opts[$k]['default'] : $v;
  }

  /**
   * Builds Options Array
   * @param null
   * @access private
   * @return void
   * @since 1.4.1
   * @author Pier-Luc Petitclerc <pL@fusi0n.org>
  */
  private function _buildOptions($init=false) {
    $this->opts = array('wppp_automate_all' => array('default' => 1,
                                                     'section' => 'automate',
                                                     'name'    => __('Automate all'),
                                                     'current'=> $this->wppp_get_option('wppp_automate_all'),
                                                     'desc'    => __('Automatic replacement of all supported media types')),
                        'wppp_automate_img' => array('default'=> 1,
                                                     'section'=> 'automate',
                                                     'name'   => __('Automate images'),
                                                     'current'=> $this->wppp_get_option('wppp_automate_img'),
                                                     'desc'   => __('Automatic replacement of image links (BMP, GIF, JPG, JPEG, PNG)')),
                        'wppp_automate_swf' => array('default'=> 1,
                                                     'section'=> 'automate',
                                                     'name'   => __('Automate flash'),
                                                     'current'=> $this->wppp_get_option('wppp_automate_swf'),
                                                     'desc'   => __('Automatic replacement of Flash video links (SWF)')),
                        'wppp_automate_mov' => array('default'=> 1,
                                                     'section'=> 'automate',
                                                     'name'   => __('Automate QuickTime'),
                                                     'current'=> $this->wppp_get_option('wppp_automate_mov'),
                                                     'desc'   => __('Automatic replacement of Quicktime video links (MOV)')),
                        'wppp_automate_yt'  => array('default'=> 1,
                                                    'section'=> 'automate',
                                                    'name'   => __('Automate YouTube'),
                                                     'current'=> $this->wppp_get_option('wppp_automate_yt'),
                                                    'desc'   => __('Automatic replacement of YouTube links')),
                        'wppp_automate_ext' => array('default'=> 0,
                                                     'section'=> 'automate',
                                                     'name'   => __('Automate iFrames'),
                                                     'current'=> $this->wppp_get_option('wppp_automate_ext'),
                                                     'desc'   => __('Automatic replacement of external iFrames')),
                        'wppp_rel'          => array('default'=> 'wp-prettyPhoto',
                                                     'section'=> 'technical',
                                                     'name'   => __('Rel value'),
                                                     'current'=> $this->wppp_get_option('wppp_rel'),
                                                     'desc'   => __('Value of the links\' "REL" attribute you want WP-prettyPhoto to look for')),
                        'wppp_speed'        => array('default'=> 'normal',
                                                     'values' => array('slow','normal','fast'),
                                                     'section'=> 'appearance',
                                                     'name'   => __('Speed'),
                                                     'current'=> $this->wppp_get_option('wppp_speed'),
                                                     'desc'   => __('The speed at which the prettyPhoto box should open')),
                        'wppp_padding'      => array('default'=> '20',
                                                     'section'=> 'appearance',
                                                     'name'   => __('Padding'),
                                                     'current'=> $this->wppp_get_option('wppp_padding'),
                                                     'desc'   => __('Padding on each side of the displayed element inside prettyPhoto\'s box. Percentage values only (0-100)')),
                        'wppp_opacity'      => array('default'=> '0.35',
                                                     'section'=> 'appearance',
                                                     'name'   => __('Opacity'),
                                                     'current'=> $this->wppp_get_option('wppp_opacity'),
                                                     'desc'   => __('Opacity of prettyPhoto\'s box. Float values between 0 and 1.0.')),
                        'wppp_title'        => array('default'=> 1,
                                                     'section'=> 'appearance',
                                                     'name'   => __('Show title'),
                                                     'current'=> $this->wppp_get_option('wppp_title'),
                                                     'desc'   => __('Show title (value of the links\' ALT attribute) inside prettyPhoto box.')),
                        'wppp_resize'       => array('default'=> 1,
                                                     'section'=> 'appearance',
                                                     'name'   => __('Allow resize'),
                                                     'current'=> $this->wppp_get_option('wppp_resize'),
                                                     'desc'   => __('Allow the prettyPhoto box to be resizeable')),
                        'wppp_counterlabel' => array('default'=> '/',
                                                     'section'=> 'appearance',
                                                     'name'   => __('Counter label'),
                                                     'current'=> $this->wppp_get_option('wppp_counterlabel'),
                                                     'desc'   => __('String value of the separator character for galleries')),
                        'wppp_theme'        => array('default'=> 'dark_rounded',
                                                     'section'=> 'appearance',
                                                     'name'   => __('Theme'),
                                                     'current'=> $this->wppp_get_option('wppp_theme'),
                                                     'values' => $this->_getThemes(),
                                                     'desc'   => __('prettyPhoto theme to use')),
                        'wppp_jsreplace'    => array('default'=> 1,
                                                     'section'=> 'technical',
                                                     'name'   => __('Replace JavaScript'),
                                                     'current'=> $this->wppp_get_option('wppp_jsreplace'),
                                                     'desc'   => __('Replace WordPress\' jQuery with bundled version')),
                        'wppp_callback'     => array('default'=> 'function(){}',
                                                     'section'=> 'technical',
                                                     'name'   => __('Callback function'),
                                                     'current'=> $this->wppp_get_option('wppp_callback'),
                                                     'desc'   => __('Callback function (MUST be "function(){YOUR_JS_CODE_HERE}")')),
                        'wppp_bottom'       => array('default'=> 0,
                                                     'section'=> 'technical',
                                                     'name'   => __('Place JavaScript in footer'),
                                                     'current'=> $this->wppp_get_option('wppp_bottom'),
                                                     'desc'   => __('Whether the prettyPhoto JavaScript code should be placed in the footer instead of the header'))
                  );
  }

  /**
   * Fetches a list of installed prettyPhoto themes
   * @param null
   * @return array Numeric array containing directory names of installed themes
   * @author Pier-Luc Petitclerc <pL@fusi0n.org>
   * @since 1.1s
   * @access private
  */
  private function _getThemes() {
    $themes = array();
    $dir = scandir(dirname(__FILE__).'/images/prettyPhoto');
    foreach ($dir as $key=>$dirname) {
      if ((strlen($dirname) > 2) && is_dir(dirname(__FILE__).'/images/prettyPhoto/'.$dirname)) { $themes[] = $dirname; }
    }
    return $themes;
  }
}

// Fire in the hole!
$wppp = new WP_prettyPhoto();
register_activation_hook(__FILE__, array(&$wppp, 'wppp_activation_hook')); 